﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Windows.Documents;
using System.IO;
using System.Security.Cryptography;

namespace ZP_IAP
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //串口信息结构体类型
        private struct ComInfo
        {
            public string portName;
            public int baudRate;
            public Parity parity;
            public int dataBits;
            public StopBits stopBits;
        }
        private ComInfo cominfo = new ComInfo();
        public bool iCOMMStatus = false;//串口状态标志位
        public SerialPort serialPort1 = null;
        private bool recvFlag = false;//避免正在接收数据时，将串口关闭
        private Ymodem.Ymodem ymodem;
        System.Threading.Thread downloadThread;
        const string upgradeCmd = "IAP REQUEST";//升级命令
        const string deviceSoftwareVisionCmd = "SOFTWARE";//读取设备软件版本信息命令        
        const string deviceUpgradeRecodeCount_Cmd = "UPGRADE_RECODE_COUNT";
        const string deviceUpgradeRecodeData_Cmd = "UPGRADE_RECODE_DATA";
        //private bool add_DataRecv_Event_Flag = false;//避免多次点击请求升级按钮时，重复注册事件
        private void Form1_Load(object sender, EventArgs e)
        {
            cmb_ComPort.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());

            cmb_ComPort.Text = cmb_ComPort.Items[0].ToString();
            cmb_BaudRate.Text = cmb_BaudRate.Items[4].ToString();
            cmb_DataBits.Text = cmb_DataBits.Items[3].ToString();
            cmb_DeviceModel.Text = cmb_DeviceModel.Items[0].ToString();

            this.txb_DeviceCommuni_Buff.TextChanged += new System.EventHandler(this.txtReceiveMsgChanged);

            rdo_HighSpeed.Checked = true;
            btn_DownloadButton.Enabled = false;//失能开始下载按钮

            timer_CheckIAP_ReturnChar = new System.Timers.Timer(500);//实例化Timer类，设置间隔时间；

            timer_CheckIAP_ReturnChar.Elapsed += new System.Timers.ElapsedEventHandler(Timerout_CheckIAP_ReturnChar);//到达时间的时候执行事件；

            timer_CheckIAP_ReturnChar.AutoReset = true;//设置是执行一次（false）还是一直执行(true)；
        }
        /// <summary>
        /// 获取设备信息和串口参数配置 
        /// </summary>
        private void InitializeComInfo()
        {
            cominfo.portName = cmb_ComPort.Text;
            cominfo.baudRate = Convert.ToInt32(cmb_BaudRate.Text);
            switch (cmb_DataBits.SelectedIndex)
            {
                case 0:
                    cominfo.dataBits = 8;
                    cominfo.parity = Parity.None;
                    cominfo.stopBits = StopBits.Two;
                    break;
                case 1:
                    cominfo.dataBits = 7;
                    cominfo.parity = Parity.Even;
                    cominfo.stopBits = StopBits.One;
                    break;
                case 2:
                    cominfo.dataBits = 7;
                    cominfo.parity = Parity.Odd;
                    cominfo.stopBits = StopBits.One;
                    break;
                case 3:
                    cominfo.dataBits = 8;
                    cominfo.parity = Parity.None;
                    cominfo.stopBits = StopBits.One;
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// 禁止修改设备信息和串口选项
        /// </summary>
        /// <param name="status"></param>
        void ComboboxEnabled(bool status)
        {
            /*设备信息*/
            this.cmb_DeviceModel.Enabled = status;
            /*串口选项*/
            cmb_ComPort.Enabled = status;
            cmb_BaudRate.Enabled = status;
            cmb_DataBits.Enabled = status;
        }
        /// <summary>
        /// 串口发送数据
        /// </summary>
        /// <param name="bParam"></param>
        /// <returns></returns>
        public bool SendData(byte[] bParam)
        {
            try
            {
                if (bParam.Length > 0)
                {
                    if (serialPort1 != null && serialPort1.IsOpen)
                    {
                        serialPort1.Write(bParam, 0, bParam.Length);
                    }
                    return true;
                }
                else
                {
                    return true;
                }
            }
            catch (System.InvalidOperationException Err)
            {
                MessageBox.Show("数据发送失败! " + Err.Message.ToString());
                return false;
            }
        }
        //private bool checkIAP_StatusFlag = false;
        private List<char> recvCharList = new List<char>();
        /// <summary>
        /// 串口接收数据回调
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void RecvData_C(object sender, SerialDataReceivedEventArgs e)
        {
            if (recvFlag) return;
            recvFlag = true;
            if (true == iCOMMStatus)
            {
                int len = serialPort1.BytesToRead;
                Byte[] readBuffer = new Byte[len];
                serialPort1.Read(readBuffer, 0, len);
                //string tempStr = "";
                for (int i = 0; i < readBuffer.Length; i++)
                {
                    recvCharList.Add(Convert.ToChar(readBuffer[i]));
                }
                Console.WriteLine(Convert.ToChar(readBuffer[0]));
            }
            recvFlag = false;
        }
        /// <summary>
        /// 打开串口
        /// </summary>
        /// <param name="portName"></param>
        /// <param name="baudRate"></param>
        /// <param name="parity"></param>
        /// <param name="dataBits"></param>
        /// <param name="stopBits"></param>
        private void Open_Serial(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
        {
            try
            {
                serialPort1 = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
                //this.serialPort1.DataReceived += new SerialDataReceivedEventHandler(RecvData_C);
                try
                {
                    serialPort1.Open();
                }
                catch (UnauthorizedAccessException ex)
                {
                    MessageBox.Show("端口占用权限不足，请以管理员身份运行", "提示", MessageBoxButtons.OK);
                }

            }
            catch (System.IO.IOException Err)
            {
                MessageBox.Show("串口初始化失败! " + Err.Message.ToString());

            }
        }
        /// <summary>
        /// 关闭串口
        /// </summary>
        private void Close_Serial()
        {
            try
            {
                if (serialPort1 != null)
                {
                    // this.serialPort1.DataReceived -= new SerialDataReceivedEventHandler(RecvData_C);
                    serialPort1.Close();
                    serialPort1 = null;
                }
            }
            catch
            {
                MessageBox.Show("串口关闭失败!", "提示框");
            }
        }

        /// <summary>
        /// 扫描串口按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnScanSerial_Click(object sender, EventArgs e)
        {
            if (false == iCOMMStatus)
            {
                this.cmb_ComPort.Items.Clear();
                //扫描电脑上的可用串口
                this.cmb_ComPort.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
                this.cmb_ComPort.Text = cmb_ComPort.Items[0].ToString();
            }            
        }
        /// <summary>
        /// 打开串口按钮按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStartCom_Click(object sender, MouseEventArgs e)
        {
            try
            {
                if (false == iCOMMStatus)
                {
                    InitializeComInfo();//得到相应串口传入的数据
                    Open_Serial(cominfo.portName, cominfo.baudRate, cominfo.parity, cominfo.dataBits, cominfo.stopBits);

                    btn_StartCom.Text = "关闭串口";
                    lbl_ConnectState.Text = "已连接";
                    lbl_state.BackColor = Color.Green;
                    ComboboxEnabled(false);
                    iCOMMStatus = true;
                }
                else
                {
                    iCOMMStatus = false;
                    Close_Serial();       //端口关闭
                    ComboboxEnabled(true);
                    lbl_state.BackColor = Color.Red;
                    btn_StartCom.Text = "打开串口";
                    lbl_ConnectState.Text = "已断开";

                }
            }
            catch (Exception ex)
            {

                Close_Serial();       //端口关闭 
                iCOMMStatus = false;
                ComboboxEnabled(true);
                btn_StartCom.Text = "打开串口";
                lbl_state.BackColor = Color.Gray;
                MessageBox.Show("打开错误：" + ex.Message);
            }
        }
        byte CheckSum(byte[] Buf, int Len)
        {

            int i = 0;
            byte sum = 0;
            byte checksum = 0;

            for (i = 0; i < Len; i++)
            {
                sum += Buf[i];
            }

            checksum = (byte)(sum & 0xff);

            return checksum;
        }
        public string GetMD5HashFromFile(string fileName, ref string MD5_Str)
        {
            try
            {
                FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                {
                    MD5 md5 = new MD5CryptoServiceProvider();
                    byte[] retVal = md5.ComputeHash(file);
                    file.Close();
                    StringBuilder sb = new StringBuilder();
                    short MD5_Sum = 0;
                    for (int i = 0; i < retVal.Length; i++)
                    {
                        sb.Append(retVal[i].ToString("X2"));//完整MD5校验字符串
                        MD5_Sum += retVal[i];//MD5
                    }
                    MD5_Str = sb.ToString();
                    return MD5_Sum.ToString("X4");
                }

            }
            catch (Exception ex)
            {
                throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
            }
        }


        /// <summary>
        /// 选择文件按钮点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// 正确的文件名：L100B_1.075.01_Release_20211104_（4字节整个bin文件的校验和）_（1字节文件名的校验和）.bin
        private void selectFileButton_Click(object sender, EventArgs e)
        {

            Button button = (Button)sender;
            if (button.Text == "选择文件")
            {
                OpenFileDialog openFileDialog = new OpenFileDialog();
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    txb_program_Info.Text = "";//清空文件信息
                    //获取文件信息

                    string path_Str = openFileDialog.FileName.ToString();//显示文件路径
                    string filename = System.IO.Path.GetFileName(openFileDialog.FileName);//获取文件名
                    string MD5_Str = "";//完整MD5校验
                    string MD5_Sum_Str_Right = GetMD5HashFromFile(openFileDialog.FileName, ref MD5_Str);//计算MD5校验和
                    FileStream fileStream = new FileStream(path_Str, FileMode.Open, FileAccess.Read);//这一句很关键，通过文件路径获取文件流
                    string fileSize = fileStream.Length.ToString();
                    byte[] file_Name_Array = System.Text.Encoding.Default.GetBytes(filename);//将文件名转化为数组

                    byte check_Sum_Byte = CheckSum(file_Name_Array, file_Name_Array.Length - 6);
                    //判断文件名和设备是否匹配
                    filename = filename.Substring(0, filename.Length-4);
                    string[] sArray = filename.Split('_');
                    if (sArray.Length < 5)
                    {
                        MessageBox.Show("bin文件名格式错误！", "系统警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        
                        fileStream.Close();
                        return;
                    }
                    string deviceNameStr = sArray[0];
                    string MD5_Sum_Str = sArray[4];//文件名上的MD5校验和
                    string CheckSum_Str = sArray[5];

                    if (deviceNameStr != cmb_DeviceModel.Text)
                    {
                        MessageBox.Show("bin文件与所选设备不匹配！", "系统警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        
                        fileStream.Close();
                        return;
                    }
                    if (MD5_Sum_Str_Right != MD5_Sum_Str)
                    {
                        MessageBox.Show("bin文件MD5校验错误！", "系统警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        
                        fileStream.Close();
                        return;
                    }
                    if (check_Sum_Byte.ToString("X2") != CheckSum_Str)
                    {
                        MessageBox.Show("bin文件名校验错误！", "系统警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        
                        fileStream.Close();
                        return;
                    }
                    //判断文件大小
                    if (int.Parse(fileSize) >= 110000)//L100_B的flash大小规划给APP程序的是110K字节
                    {
                        MessageBox.Show("bin文件的大小超过FLASH的最大容量！", "系统警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        
                        fileStream.Close();//关闭文件流
                        return;
                    }
                    this.txb_APP_FileBath.Text = path_Str;
                    txb_program_Info.Text = "文件名：" + filename + "\r\n\r\n" + "文件大小：" + fileSize + " byte\r\n\r\n" + "MD5校验：" + MD5_Str;
                }
            }
        }

        /// <summary>
        /// 下载按钮点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void downloadButton_Click(object sender, EventArgs e)
        {
            Button button = (Button)sender;

            if (txb_APP_FileBath.Text == "")
            {
                MessageBox.Show("文件路径不能为空！", "系统警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (button.Text == "开始下载")
            {
                while (recvFlag) ;
                timer_CheckIAP_ReturnChar.Stop();//关闭检查字符C的定时器
                Console.WriteLine("Timer close");
                this.serialPort1.DataReceived -= new SerialDataReceivedEventHandler(RecvData_C);
                Console.WriteLine("delete DataReceivedEvent");

                button.Text = "正在下载";//防止多次重复点击
                ymodem = new Ymodem.Ymodem();
                ymodem.Path = txb_APP_FileBath.Text.ToString();
                ymodem.SerialPort = serialPort1;
                downloadThread = new System.Threading.Thread(ymodem.YmodemUploadFile);
                ymodem.NowDownloadProgressEvent += new EventHandler(NowDownloadProgressEvent);
                ymodem.DownloadResultEvent += new EventHandler(DownloadFinishEvent);
                downloadThread.Start();
                //buttonRequestUpgrade.Enabled = false;//禁用请求升级按钮
                //buttonReadAPP_Version.Enabled = false;//禁用读取设备信息按钮
                btn_StartCom.Enabled = false;//禁用串口操作
            }
        }
        #region 下载进度委托及事件响应
        private delegate void NowDownloadProgress(int nowValue);
        private void NowDownloadProgressEvent(object sender, EventArgs e)
        {
            int value = Convert.ToInt32(sender);
            NowDownloadProgress count = new NowDownloadProgress(UploadFileProgress);
            this.Invoke(count, value);
        }
        private void UploadFileProgress(int count)
        {
            bar_DownloadProgress.Value = count;
        }
        #endregion
        #region 下载完成委托及事件响应
        private delegate void DownloadFinish(bool finish);
        private void DownloadFinishEvent(object sender, EventArgs e)
        {
            bool finish = (Boolean)sender;
            DownloadFinish status = new DownloadFinish(UploadFileResult);
            this.Invoke(status, finish);
        }
        private void UploadFileResult(bool result)
        {
            if (result == true)
            {
                MessageBox.Show("下载成功");
                this.btn_DownloadButton.Text = "开始下载";
                this.bar_DownloadProgress.Value = 0;
            }
            else
            {
                MessageBox.Show("下载失败");
                this.btn_DownloadButton.Text = "开始下载";
                this.bar_DownloadProgress.Value = 0;
            }
            rdo_LowSpeed.Enabled = true;
            rdo_HighSpeed.Enabled = true;
            btn_ReadUpgradeRecode.Enabled = true;
            btn_RequestUpgrade.Enabled = true;//使能请求升级按钮
            btn_ReadAPP_Version.Enabled = true;
            btn_StartCom.Enabled = true;//使能串口操作
            lbl_BootloaderLight.BackColor = Color.Red;
            lbl_BootloaderStatus.Text = "";
            btn_DownloadButton.Enabled = false;//禁用下载按钮

        }
        #endregion
        private System.Timers.Timer timer_CheckIAP_ReturnChar = null;
        /// <summary>
        /// 请求升级按钮点击事件
        /// Note:会切换到UI设定的串口格式发送命令，再按照UI设定的高低速切换串口，再启动定时器监听串口接收到的数据是否是C
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonRequestUpgrade_Click(object sender, EventArgs e)
        {
            if (iCOMMStatus)
            {
                try//根据UI界面选择的串口参数，切换串口波特率
                {
                    Close_Serial();
                    InitializeComInfo();//得到相应串口传入的数据
                    Open_Serial(cominfo.portName, cominfo.baudRate, cominfo.parity, cominfo.dataBits, cominfo.stopBits);
                    Console.WriteLine("Open_Serial(cominfo.portName, cominfo.baudRate, cominfo.parity, cominfo.dataBits, cominfo.stopBits)");
                }
                catch (Exception ex)
                {
                    Close_Serial();
                    MessageBox.Show("串口错误：" + ex.Message);
                }
                //发送升级命令
                if (this.serialPort1.IsOpen)
                {
                    //生成命令
                    byte[] cmdArray = new byte[14];
                    cmdArray[0] = 0XFF;
                    cmdArray[1] = 0X5A;
                    byte[] strArray = System.Text.Encoding.Default.GetBytes(upgradeCmd);
                    for (uint i = 0; i < strArray.Length; i++)
                    {
                        cmdArray[2 + i] = strArray[i];
                    }
                    //生成下载速度
                    if (rdo_LowSpeed.Checked)
                    {
                        cmdArray[13] = Convert.ToByte('L');
                    }
                    else
                    {
                        cmdArray[13] = Convert.ToByte('H');
                    }
                    //计算CRC
                    byte[] CRC = new byte[2];
                    CRC = Ymodem.Ymodem.ComputeChecksumBytes(cmdArray, cmdArray.Length);
                    serialPort1.Write(cmdArray, 0, cmdArray.Length);
                    serialPort1.Write(CRC, 0, CRC.Length);
                    Console.WriteLine("send upgrade cmd");
                }
                try//根据UI界面选择的下载速度，切换串口波特率
                {
                    Close_Serial();
                    if (rdo_LowSpeed.Checked)
                    {
                        Open_Serial(cmb_ComPort.Text, 19200, Parity.None, 8, StopBits.Two);
                        Console.WriteLine("Open_Serial(com_port.Text, 19200, Parity.None, 8, StopBits.Two);");
                    }
                    else
                    {
                        Open_Serial(cmb_ComPort.Text, 230400, Parity.None, 8, StopBits.Two);
                        Console.WriteLine("Open_Serial(com_port.Text, 230400, Parity.None, 8, StopBits.Two)");
                    }
                    /*这里不需要考虑串口接收事件重复添加，因为前面有串口开关的操作（个人想法，待验证！！！）*/
                    this.serialPort1.DataReceived += new SerialDataReceivedEventHandler(RecvData_C);
                    Console.WriteLine("add_DataRecv_Event");
                }
                catch (Exception ex)
                {
                    Close_Serial();
                    MessageBox.Show("串口错误：" + ex.Message);
                }

                /*打开定时器去检查串口有没有数据,开始下载时关闭定时器*/
                timer_CheckIAP_ReturnChar.Start();
                //timerWaitFailCount = 0;
            }
            else
            {
                MessageBox.Show("请先打开串口！", "系统警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }
        private int IAP_ReturnCharFault_Count = 0;
        /// <summary>
        /// 定时器溢出回调函数：检查设定时间内设备IAP发送的数据是否正确，从而决定是否允许升级和下载
        /// Note:检测到错误，会关闭定时器，并禁止升级和下载；直到用户再次点击UI的请求升级按钮，重新启动定时器进行检查
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        public void Timerout_CheckIAP_ReturnChar(object source, System.Timers.ElapsedEventArgs e)
        {
            if (recvFlag) return;//线程锁            
            recvFlag = true;//加锁访问recvCharList
            bool ret = true;
           
            if (0 == recvCharList.Count)
            {
                ret = false;
            }
            else
            {
                foreach (char ch in recvCharList)
                {
                    if ('C' != ch)
                    {
                        ret = false;
                        break;
                    }
                }
            }
            recvCharList.Clear();

            recvFlag = false;//解锁
            if (false == ret)
            {
                if (++IAP_ReturnCharFault_Count >= 6)
                {
                    //超过3S没收到C或收到的不是C
                    this.Invoke(new Action(() =>
                    {
                        lbl_BootloaderLight.BackColor = Color.Red;
                        lbl_BootloaderStatus.Text = "";
                        btn_DownloadButton.Enabled = false;//失能开始下载按钮
                        //安全起见，恢复下列操作
                        rdo_LowSpeed.Enabled = true;
                        rdo_HighSpeed.Enabled = true;
                        btn_ReadAPP_Version.Enabled = true;
                        btn_ReadUpgradeRecode.Enabled = true;
                    }));
                    IAP_ReturnCharFault_Count = 0;
                    timer_CheckIAP_ReturnChar.Stop();
                }
                else
                {
                    //不管
                }

            }
            else
            {
                IAP_ReturnCharFault_Count = 0;//清零错误计数
                this.Invoke(new Action(() =>
                {
                    lbl_BootloaderLight.BackColor = Color.Green;
                    lbl_BootloaderStatus.Text = "允许升级";
                    btn_DownloadButton.Enabled = true;//失能开始下载按钮
                    //安全起见，禁用下面操作
                    rdo_LowSpeed.Enabled = false;
                    rdo_HighSpeed.Enabled = false;
                    btn_ReadAPP_Version.Enabled = false;
                    btn_ReadUpgradeRecode.Enabled = false;
                }));
                
            }
        }
        /// <summary>
        /// 读取设备信息按钮按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonReadAPP_Version_Click(object sender, EventArgs e)
        {
            if (iCOMMStatus)
            {
                Parity currentParity = serialPort1.Parity;
                StopBits currentStopBits = serialPort1.StopBits;
                int currentDataBits = serialPort1.DataBits;
                int currentBaudrate = serialPort1.BaudRate;
                string currentPortName = serialPort1.PortName;
                InitializeComInfo();
                if (cominfo.portName != currentPortName ||
                    cominfo.parity != currentParity ||
                    cominfo.baudRate != currentBaudrate ||
                    cominfo.dataBits != currentDataBits ||
                    cominfo.stopBits != currentStopBits)
                {
                    try//根据UI界面选择的串口参数，切换串口波特率
                    {
                        Close_Serial();
                        InitializeComInfo();//得到相应串口传入的数据
                        Open_Serial(cominfo.portName, cominfo.baudRate, cominfo.parity, cominfo.dataBits, cominfo.stopBits);
                        Console.WriteLine("Open_Serial(cominfo.portName, cominfo.baudRate, cominfo.parity, cominfo.dataBits, cominfo.stopBits)");
                    }
                    catch (Exception ex)
                    {
                        Close_Serial();
                        MessageBox.Show("串口错误：" + ex.Message);
                    }
                }
                lastResponse_Len = 0;
                currentRespomse_len = 0;
                //注意：这里需要考虑串口接收事件重复添加的情况，因为前面的串口开关操作不一定执行！！！
                this.serialPort1.DataReceived += new SerialDataReceivedEventHandler(RecvData_Response);
                Console.WriteLine("add_DataRecv_Event");
                //发送读取命令
                if (this.serialPort1.IsOpen)
                {
                    //生成命令
                    byte[] cmdArray = new byte[2 + 1 + deviceSoftwareVisionCmd.Length];
                    cmdArray[0] = 0XFF;
                    cmdArray[1] = 0XA5;
                    cmdArray[2] = 0X00;
                    byte[] strArray = System.Text.Encoding.Default.GetBytes(deviceSoftwareVisionCmd);
                    for (uint i = 0; i < strArray.Length; i++)
                    {
                        cmdArray[3 + i] = strArray[i];
                    }
                    //计算CRC
                    byte[] CRC = new byte[2];
                    CRC = Ymodem.Ymodem.ComputeChecksumBytes(cmdArray, cmdArray.Length);
                    serialPort1.Write(cmdArray, 0, cmdArray.Length);
                    serialPort1.Write(CRC, 0, CRC.Length);
                    Console.WriteLine("send read software cmd");
                    //开一个线程去解析设备的响应数据，线程执行完自动关闭
                    System.Threading.Thread parseDeviceResponseInfo_Thread = new System.Threading.Thread(parseDeviceResponseInfo_Fun);
                    parseDeviceResponseInfo_Thread.Start();
                }
            }
            else
            {
                MessageBox.Show("请先打开串口！", "系统警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private bool RecvData_Response_Flag = false;//设备相应数据的线程锁
        private byte[] RecvData_Response_Buff = new byte[100];
        private int lastResponse_Len = 0;//用之前需要将这个值清零，避免对这次通信产生影响
        private int currentRespomse_len = 0;//同上
        void RecvData_Response(object sender, SerialDataReceivedEventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                RecvData_Response_Flag = true;


                currentRespomse_len = serialPort1.BytesToRead;
                if ((currentRespomse_len + lastResponse_Len) > RecvData_Response_Buff.Length)
                {
                    Console.WriteLine("Recv data is too long!  Return");
                    RecvData_Response_Flag = false;
                    return;
                }
                serialPort1.Read(RecvData_Response_Buff, lastResponse_Len, currentRespomse_len);
                lastResponse_Len += currentRespomse_len;

                string tmp_Str = "";
                for (int i = 0; i < RecvData_Response_Buff.Length; i++)
                {
                    tmp_Str += Convert.ToChar(RecvData_Response_Buff[i]);
                }
                Console.WriteLine(tmp_Str);

                RecvData_Response_Flag = false;
            }
        }
        /// <summary>
        /// 读取设备版本号时解析设备返回数据
        /// </summary>
        void parseDeviceResponseInfo_Fun()
        {
            try 
            {
                System.Threading.Thread.Sleep(100);
                while (RecvData_Response_Flag) ;//安全访问RecvData_Response_Buff
                string tmp_Str = "";
                if (lastResponse_Len <= 4)
                {
                    tmp_Str = "设备无响应！";
                    this.Invoke(new Action(() =>
                    {
                        txb_DeviceCommuni_Buff.Text += (tmp_Str);
                        txb_DeviceCommuni_Buff.AppendText(Environment.NewLine);
                        txb_DeviceCommuni_Buff.AppendText(Environment.NewLine);
                    }));
                    return;
                }

                byte[] r_CRC = Ymodem.Ymodem.ComputeChecksumBytes(RecvData_Response_Buff, lastResponse_Len - 2);
                if (!(r_CRC[0] == RecvData_Response_Buff[lastResponse_Len - 2]) || !(r_CRC[1] == RecvData_Response_Buff[lastResponse_Len - 1]))
                {
                    tmp_Str = "数据校验错误！";
                    this.Invoke(new Action(() =>
                    {
                        txb_DeviceCommuni_Buff.Text += (tmp_Str);
                        txb_DeviceCommuni_Buff.AppendText(Environment.NewLine);
                        txb_DeviceCommuni_Buff.AppendText(Environment.NewLine);
                    }));

                }
                else
                {
                    for (int i = 3; i < lastResponse_Len - 2; i++)
                    {
                        tmp_Str += Convert.ToChar(RecvData_Response_Buff[i]);
                    }
                    this.Invoke(new Action(() =>
                    {
                        txb_DeviceCommuni_Buff.Text += ("软件版本号：" + tmp_Str);
                        txb_DeviceCommuni_Buff.AppendText(Environment.NewLine);
                        txb_DeviceCommuni_Buff.AppendText(Environment.NewLine);
                    }));
                }
            }
            finally
            {
                lastResponse_Len = 0;
                currentRespomse_len = 0;
                this.serialPort1.DataReceived -= new SerialDataReceivedEventHandler(RecvData_Response);//添加多个会造成线程拿不到数据          
            }           

        }

        private void buttonReadUpgradeRecode_Click(object sender, EventArgs e)
        {
            System.Threading.Thread readUpgradeRecode_Thread = new System.Threading.Thread(ReadUpgradeRecode_Fun);
            readUpgradeRecode_Thread.Start();
            
        }
        void RecvData_UpgradeRecodeResponse(object sender, SerialDataReceivedEventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                RecvData_Response_Flag = true;


                currentRespomse_len = serialPort1.BytesToRead;
                if ((currentRespomse_len + lastResponse_Len) > RecvData_Response_Buff.Length)
                {
                    Console.WriteLine("Recv data is too long!  Return");
                    RecvData_Response_Flag = false;
                    return;
                }
                serialPort1.Read(RecvData_Response_Buff, lastResponse_Len, currentRespomse_len);
                lastResponse_Len += currentRespomse_len;

                string tmp_Str = "";
                for (int i = 0; i < RecvData_Response_Buff.Length; i++)
                {
                    //tmp_Str += Convert.ToChar(RecvData_Response_Buff[i]);

                    tmp_Str += RecvData_Response_Buff[i].ToString("X2");
                    tmp_Str += ' ';
                }
                Console.WriteLine(tmp_Str);

                RecvData_Response_Flag = false;
            }
        }
        private byte recodeIndex = 0;
        void ReadUpgradeRecode_Fun()
        {
            if (iCOMMStatus)
            {
                //安全起见，限制其他按钮的使用
                this.Invoke(new Action(() =>
                {
                    btn_ReadUpgradeRecode.Enabled = false;
                    btn_ReadAPP_Version.Enabled = false;
                    btn_RequestUpgrade.Enabled = false;
                    txb_DeviceCommuni_Buff.Text += "\\****************************************************************************\\\r\n";
                }));

                Parity currentParity = serialPort1.Parity;
                StopBits currentStopBits = serialPort1.StopBits;
                int currentDataBits = serialPort1.DataBits;
                int currentBaudrate = serialPort1.BaudRate;
                string currentPortName = serialPort1.PortName;
                this.Invoke(new Action(() =>
                {
                    InitializeComInfo();
                }));

                if (cominfo.portName != currentPortName ||
                    cominfo.parity != currentParity ||
                    cominfo.baudRate != currentBaudrate ||
                    cominfo.dataBits != currentDataBits ||
                    cominfo.stopBits != currentStopBits)
                {
                    try//根据UI界面选择的串口参数，切换串口波特率
                    {
                        Close_Serial();
                        //InitializeComInfo();//得到相应串口传入的数据
                        Open_Serial(cominfo.portName, cominfo.baudRate, cominfo.parity, cominfo.dataBits, cominfo.stopBits);
                        Console.WriteLine("Open_Serial(cominfo.portName, cominfo.baudRate, cominfo.parity, cominfo.dataBits, cominfo.stopBits)");
                    }
                    catch (Exception ex)
                    {
                        Close_Serial();
                        MessageBox.Show("串口错误：" + ex.Message);
                    }
                }

                //注意：这里需要考虑串口接收事件重复添加的情况，因为前面的串口开关操作不一定执行！！！
                this.serialPort1.DataReceived += new SerialDataReceivedEventHandler(RecvData_UpgradeRecodeResponse);
                Console.WriteLine("Add RecvData_UpgradeRecodeResponse");
                //发送读取命令
                if (this.serialPort1.IsOpen)
                {
                    lastResponse_Len = 0;
                    currentRespomse_len = 0;
                    //生成命令
                    byte[] cmdArray = new byte[2 + 2 + deviceUpgradeRecodeCount_Cmd.Length];
                    cmdArray[0] = 0XFF;
                    cmdArray[1] = 0XA5;
                    cmdArray[2] = 0X01;
                    cmdArray[3] = 0X02;
                    byte[] strArray = System.Text.Encoding.Default.GetBytes(deviceUpgradeRecodeCount_Cmd);
                    for (uint i = 0; i < strArray.Length; i++)
                    {
                        cmdArray[4 + i] = strArray[i];
                    }
                    //计算CRC
                    byte[] CRC = new byte[2];
                    CRC = Ymodem.Ymodem.ComputeChecksumBytes(cmdArray, cmdArray.Length);
                    //串口发送
                    serialPort1.Write(cmdArray, 0, cmdArray.Length);
                    serialPort1.Write(CRC, 0, CRC.Length);
                    Console.WriteLine("send read upgrade recode count cmd");
                    /*解析出升级记录有多少条*/
                    Console.WriteLine("readCount:" + "lastResponse_Len" + lastResponse_Len.ToString() + "currentRespomse_len" + currentRespomse_len.ToString());
                    byte count = parseUpgradeRecode_Count();


                    recodeIndex = 0;//升级记录的序号
                    while (count-- != 0)
                    {
                        lastResponse_Len = 0;
                        currentRespomse_len = 0;
                        //生成命令
                        cmdArray = new byte[2 + 2 + 1 + deviceUpgradeRecodeData_Cmd.Length];
                        cmdArray[0] = 0XFF;
                        cmdArray[1] = 0XA5;
                        cmdArray[2] = 0X01;
                        cmdArray[3] = 0X04;
                        cmdArray[4] = ++recodeIndex;
                        strArray = System.Text.Encoding.Default.GetBytes(deviceUpgradeRecodeData_Cmd);
                        for (uint i = 0; i < strArray.Length; i++)
                        {
                            cmdArray[5 + i] = strArray[i];
                        }
                        //计算CRC
                        CRC = new byte[2];
                        CRC = Ymodem.Ymodem.ComputeChecksumBytes(cmdArray, cmdArray.Length);
                        //串口发送
                        serialPort1.Write(cmdArray, 0, cmdArray.Length);
                        serialPort1.Write(CRC, 0, CRC.Length);
                        Console.WriteLine("send read upgrade recode data cmd");
                        /*解析出每一条升级记录*/
                        Console.WriteLine("count" + count.ToString() + "lastResponse_Len" + lastResponse_Len.ToString() + "currentRespomse_len" + currentRespomse_len.ToString());
                        parseUpgradeRecode_Data();

                    }
                    this.serialPort1.DataReceived -= new SerialDataReceivedEventHandler(RecvData_UpgradeRecodeResponse);//添加多个会造成线程拿不到数据          
                    Console.WriteLine("Delete RecvData_UpgradeRecodeResponse");
                }
                //取消其他按钮的使用限制
                this.Invoke(new Action(() =>
                {
                    btn_ReadUpgradeRecode.Enabled = true;
                    btn_ReadAPP_Version.Enabled = true;
                    btn_RequestUpgrade.Enabled = true;
                    txb_DeviceCommuni_Buff.Text += "\\****************************************************************************\\\r\n";
                }));
            }
            else
            {
                MessageBox.Show("请先打开串口！", "系统警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            
            
        }
        byte parseUpgradeRecode_Count()
        {
            try
            {
                System.Threading.Thread.Sleep(200);
                while (RecvData_Response_Flag) ;//安全访问RecvData_Response_Buff
                Console.WriteLine("parse count" + "lastResponse_Len" + lastResponse_Len.ToString() + "currentRespomse_len" + currentRespomse_len.ToString());
                int recvLenSum = lastResponse_Len;
                if ((recvLenSum) <= 4)
                {
                    return 0;
                }
                else
                {
                    //进行CRC校验
                    byte[] CRC = new byte[2];
                    CRC = Ymodem.Ymodem.ComputeChecksumBytes(RecvData_Response_Buff, recvLenSum - 2);
                    if ((CRC[0] != RecvData_Response_Buff[recvLenSum - 2]) || (CRC[1] != RecvData_Response_Buff[recvLenSum - 1]))
                    {
                        return 0;
                    }
                    return RecvData_Response_Buff[4];
                }
            }
            finally
            {
                lastResponse_Len = 0;
                currentRespomse_len = 0;
            }
            
        }
        void parseUpgradeRecode_Data()
        {
            System.Threading.Thread.Sleep(200);
            while (RecvData_Response_Flag) ;//安全访问RecvData_Response_Buff
            Console.WriteLine("parse data" + "lastResponse_Len" + lastResponse_Len.ToString() + "currentRespomse_len" + currentRespomse_len.ToString());
            int recvLenSum = lastResponse_Len;
            string tmp_Str = "";
            if ((lastResponse_Len + currentRespomse_len) <= 4)
            {
                tmp_Str = "设备无响应！";
                this.Invoke(new Action(() =>
                {
                    txb_DeviceCommuni_Buff.Text += (tmp_Str);
                    txb_DeviceCommuni_Buff.AppendText(Environment.NewLine);
                }));
            }
            else
            {
                //进行CRC校验
                byte[] CRC = new byte[2];
                CRC = Ymodem.Ymodem.ComputeChecksumBytes(RecvData_Response_Buff, recvLenSum - 2);
                if ((CRC[0] != RecvData_Response_Buff[recvLenSum - 2]) || (CRC[1] != RecvData_Response_Buff[recvLenSum - 1]))
                {
                   
                    tmp_Str = "数据校验错误！";
                    this.Invoke(new Action(() =>
                    {
                        txb_DeviceCommuni_Buff.Text += (tmp_Str);
                        txb_DeviceCommuni_Buff.AppendText(Environment.NewLine);
                    }));
                }
                string name_Str = "";
                string time_Str = "";
                char c = new char();
                int i = 0;
                for ( i = 5; i < lastResponse_Len - 2; i++)
                {
                    c = Convert.ToChar(RecvData_Response_Buff[i]);
                    if ('\0' == c)
                    {
                        break;
                    }
                    else
                    {
                        name_Str += c;    
                    }
                }
                int j = i + 1;
                for (; j < lastResponse_Len - 2; j++)
                {
                    time_Str += Convert.ToChar(RecvData_Response_Buff[j]);
                }

                this.Invoke(new Action(() =>
                {
                    txb_DeviceCommuni_Buff.Text += (recodeIndex.ToString("D2")+". APP升级记录：" + name_Str + ' ' + time_Str);
                    txb_DeviceCommuni_Buff.AppendText(Environment.NewLine);
                }));                
            }
            lastResponse_Len = 0;
            currentRespomse_len = 0;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.txb_DeviceCommuni_Buff.Text = "";
        }

        private void txtReceiveMsgChanged(object sender, EventArgs e)
        {
            //文本框选中的起始点在最后
            txb_DeviceCommuni_Buff.SelectionStart = txb_DeviceCommuni_Buff.TextLength;
            //将控件内容滚动到当前插入符号位置
            txb_DeviceCommuni_Buff.ScrollToCaret();
        }

        private void txb_DeviceCommuni_Buff_TextChanged(object sender, EventArgs e)
        {

        }

        private void label5_Click(object sender, EventArgs e)
        {

        }
    }
}
